/*
 * DBTable_Logs.c
 *      Author: DePhille
 */

#include "DBTable_Logs.h"


/**
 * Makes a new Logs table with the given name.
 *
 * @param	tblName	THe name for the new Logs table.
 * @returns	True on success, False otherwise.
 */
static gboolean PC_DBTable_Logs_MakeTable(const gchar* tblName) {
	gchar*	query;	// Clean-up: Yes

	// Check input:
	if (!tblName) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_MakeTable: Missing 'tblName' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if(!pc_logDB) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_MakeTable: Unable to find active DB connection.\r\n");
		return FALSE;
	}

	// Prepare query:
	query = g_strdup_printf("CREATE TABLE %s ("
			"recipient VARCHAR(100) NOT NULL,"
			"startDate UNSIGNED INT(10) NOT NULL,"
			"revision UNSIGNED INT(10) NOT NULL,"
			"lastChange UNSIGNED INT(10) NOT NULL,"
			"fileName VARCHAR(500) NOT NULL,"
			"PRIMARY KEY (recipient, startDate),"
			"UNIQUE (fileName)"
			");",
			tblName);

	// Execute query
	if (!PC_LogDB_Query(query)) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_MakeTable: Unable to make new Logs table '%s'.\r\n", tblName);
		g_free(query);
		return FALSE;
	} else {
		g_free(query);
		return TRUE;
	}
}


/**
 * Fetches one result row as a MiniLog.
 *
 * @param	stmt	The SQL statement holding a row.
 * @returns	One MiniLog extracted from the row.
 */
static PC_MiniLog*	PC_DBTable_Logs_FetchOneMiniLog(sqlite3_stmt* stmt) {
	int				sqlCode;	// Clean-up: No
	PC_MiniLog*		miniLog;	// Clean-up: No
	int				colCount;	// Clean-up: No
	int				curCol;		// Clean-up: No
	const gchar*	colName;	// Clean-up: No

	// Check input:
	if (!stmt) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_FetchOneMiniLog: Missing 'stmt' parameter.\r\n");
		return NULL;
	}

	// Fetch one row:
	sqlCode = sqlite3_step(stmt);
	if (sqlCode == SQLITE_DONE) {
		// No more results available:
		return NULL;
	} else if (sqlCode != SQLITE_ROW) {
		// Error occured:
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchOneMiniLog: Unable to fetch row from statement.\r\n");
		return NULL;
	}

	// Prepare minilog object:
	miniLog = PC_MiniLog_New();
	if (!miniLog) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchOneMiniLog: Unable to allocate miniLog object.\r\n");
		return NULL;
	}

	// Cycle trough columns:
	colCount = sqlite3_column_count(stmt);
	for (curCol = 0; curCol < colCount; curCol++) {
		// Fetch column name:
		colName = sqlite3_column_name(stmt, curCol);
		if (strcmp(colName, "fileName") == 0) {
			miniLog->fileName = g_strdup((const gchar*) (sqlite3_column_text(stmt, curCol)));
		} else if (strcmp(colName, "lastChange") == 0) {
			miniLog->lastChange = sqlite3_column_int(stmt, curCol);
		} else {
			purple_debug_warning("PidginCote", "PC_DBTable_Logs_FetchOneMiniLog: Unknown column '%s'.\r\n", colName);
		}
	}

	// Return result:
	return miniLog;
}


/**
 * Fetches an entire logTable as a GList of MiniLogs.
 *
 * @param	account	The account for which to fetch the logs.
 * @returns	A GList with all the MiniLogs in the table.
 */
static GList* PC_DBTable_Logs_FetchMiniLogs(const PurpleAccount* account) {
	sqlite3_stmt*	stmt;		// Clean-up: Yes
	gchar*			tblName;	// Clean-up: Yes
	gchar*			query;		// Clean-up: Yes
	GList*			retList;	// Clean-up: No
	PC_MiniLog*		miniLog;	// Clean-up: No

	// Check input:
	if (!account) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_FetchMiniLogs: Missing 'account' parameter.\r\n");
		return NULL;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchMiniLogs: Unable to find active DB connection.\r\n");
		return NULL;
	}

	// Get table name:
	tblName = PC_LogDB_GetTableName(account->protocol_id, PC_Util_ParseUsername(account->username));
	if (!tblName) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchMiniLogs: Unable to fetch table name.\r\n");
		return NULL;
	}

	// Prepare query:
	query = g_strdup_printf("SELECT fileName, lastChange FROM %s ORDER BY fileName DESC;", tblName);

	// Make statement:
	stmt = NULL;
	if (sqlite3_prepare_v2(pc_logDB, query, -1, &stmt, NULL) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchMiniLogs: Unable to prepare statement due to SQLite error.\r\n");
		return NULL;
	} else if (!stmt) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchMiniLogs: Unable to prepare statement due to unknown error.\r\n");
		return NULL;
	}

	// Fetch results:
	retList = NULL;
	miniLog = PC_DBTable_Logs_FetchOneMiniLog(stmt);
	while (miniLog) {
		// Prepend to list:
		retList = g_list_prepend(retList, miniLog);

		// Fetch next log:
		miniLog = PC_DBTable_Logs_FetchOneMiniLog(stmt);
	}

	// Clean-up:
	g_free(query);
	g_free(tblName);
	sqlite3_finalize(stmt);

	// Return:
	return retList;
}


/**
 * Fetches one result row as a PC_Log.
 * 	Attributes log->protocol and log->account are to be filled in by the caller.
 *
 * @param	stmt	The SQL statement holding a row.
 * @returns	One PC_Log extracted from the row.
 */
static PC_Log*	PC_DBTable_Logs_FetchOne(sqlite3_stmt* stmt) {
	int				sqlCode;	// Clean-up: No
	PC_Log*			log;		// Clean-up: No
	int				colCount;	// Clean-up: No
	int				curCol;		// Clean-up: No
	const gchar*	colName;	// Clean-up: No

	// Check input:
	if (!stmt) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_FetchOne: Missing 'stmt' parameter.\r\n");
		return NULL;
	}

	// Fetch one row:
	sqlCode = sqlite3_step(stmt);
	if (sqlCode == SQLITE_DONE) {
		// No more results available:
		return NULL;
	} else if (sqlCode != SQLITE_ROW) {
		// Error occured:
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchOne: Unable to fetch row from statement.\r\n");
		return NULL;
	}

	// Prepare log object:
	log = PC_Log_New();
	if (!log) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FetchOne: Unable to allocate Log object.\r\n");
		return NULL;
	}

	// Cycle trough columns:
	colCount = sqlite3_column_count(stmt);
	for (curCol = 0; curCol < colCount; curCol++) {
		// Fetch column name:
		colName = sqlite3_column_name(stmt, curCol);

		// Recipient
		if (strcmp(colName, "recipient") == 0) {
			log->recipient = g_strdup((const gchar*) (sqlite3_column_text(stmt, curCol)));

		// StartDate:
		} else if (strcmp(colName, "startDate") == 0) {
			log->startTime = sqlite3_column_int(stmt, curCol);

		// Revision:
		} else if (strcmp(colName, "revision") == 0) {
			log->revision = sqlite3_column_int(stmt, curCol);

		// FileName:
		} else if (strcmp(colName, "fileName") == 0) {
			log->fileName = g_strdup((const gchar*) (sqlite3_column_text(stmt, curCol)));

		// LastChange:
		} else if (strcmp(colName, "lastChange") == 0) {
			log->lastChange = sqlite3_column_int(stmt, curCol);

		// Unknown column:
		} else {
			purple_debug_warning("PidginCote", "PC_DBTable_Logs_FetchOne: Unknown column '%s'.\r\n", colName);
		}
	}

	// Return result:
	return log;
}


/**
 * Fill in the given log by filling in it's data with the data in the database.
 *
 * @param	log	The log to be completed (filled in).
 * @returns	True on success, false otherwise.
 */
static gboolean	PC_DBTable_Logs_FillIn(PC_Log* log) {
	gchar*			sqlID;		// Clean-up: Yes
	gchar*			tblName;	// Clean-up: Yes
	gchar*			query;		// Clean-up: Yes
	sqlite3_stmt*	stmt;		// Clean-up: Yes
	PC_Log*			dbLog;		// Clean-up: Yes

	// Check input:
	if (!log) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_FillIn: Missing 'log' parameter.\r\n");
		return FALSE;
	} else if (!log->protocol) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_FillIn: Missing 'log->protocol' parameter.\r\n");
		return FALSE;
	} else if (!log->account) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_FillIn: Missing 'log->account' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FillIn: Unable to find active DB connection.\r\n");
		return FALSE;
	}

	// Fetch sqlID:
	sqlID = PC_Log_GetSQLID(log);
	if (!sqlID) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FillIn: Unable to get sqlID.\r\n");
		return FALSE;
	}

	// Fetch table name:
	tblName = PC_LogDB_GetTableName(log->protocol, log->account);
	if (!tblName) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FillIn: Unable to get tblName.\r\n");
		return FALSE;
	}

	// Prepare query:
	query = g_strdup_printf("SELECT * FROM %s WHERE %s LIMIT 1", tblName, sqlID);

	// Clean-up:
	g_free(tblName);
	g_free(sqlID);

	// Make statement:
	stmt = NULL;
	if (sqlite3_prepare_v2(pc_logDB, query, -1, &stmt, NULL) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FillIn: Unable to prepare statement due to SQLite error.\r\n");
		return FALSE;
	} else if (!stmt) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_FillIn: Unable to prepare statement due to unknown error.\r\n");
		return FALSE;
	}

	// Fetch one PC_Log:
	dbLog = PC_DBTable_Logs_FetchOne(stmt);

	// Clean-up:
	g_free(query);
	sqlite3_finalize(stmt);

	// Check dbLog:
	if (!dbLog) {
		return FALSE;
	} else {
		// Clear attributes:
		if (log->fileName) {
			g_free(log->fileName);
			log->fileName = NULL;
		}
		if (log->recipient) {
			g_free(log->recipient);
			log->recipient = NULL;
		}

		// Copy attributes:
		log->fileName = g_strdup(dbLog->fileName);
		log->lastChange = dbLog->lastChange;
		log->recipient = g_strdup(dbLog->recipient);
		log->revision = dbLog->revision;
		log->startTime = dbLog->startTime;

		// Clean-up:
		PC_Log_Free(dbLog);

		// Return success:
		return TRUE;
	}
}



/**
 * Inserts a new PC_Log in the database.
 *
 * @param	log	The PC_Log to be inserted.
 * @returns True on success, false otherwise.
 */
static gboolean	PC_DBTable_Logs_Insert(const PC_Log* log) {
	gchar*			tblName;	// Clean-up: Yes
	char*			query;		// Clean-up: Yes

	// Check input:
	if (!log) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log' parameter.\r\n");
		return FALSE;
	} else if (!log->protocol) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log->protocol' parameter.\r\n");
		return FALSE;
	} else if (!log->account) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log->account' parameter.\r\n");
		return FALSE;
	} else if (!log->recipient) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log->recipient' parameter.\r\n");
		return FALSE;
	} else if (!log->startTime) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log->startTime' parameter.\r\n");
		return FALSE;
	} else if (!log->fileName) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log->fileName' parameter.\r\n");
		return FALSE;
	} else if (!log->lastChange) {
		purple_debug_warning("PidginCote", "PC_LogDB_Insert: Missing 'log->lastChange' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_LogDB_Insert: Unable to find an active DB connection.\r\n");
		return FALSE;
	}

	// Fetch table name:
	tblName = PC_LogDB_GetTableName(log->protocol, log->account);
	if (!tblName) {
		purple_debug_error("PidginCote", "PC_LogDB_Insert: Unable to get TableName.\r\n");
		return FALSE;
	}

	// Prepare query:
	query = sqlite3_mprintf("INSERT INTO %s (recipient, startDate, revision, lastChange, fileName) VALUES (%Q, %i, %i, %i, %Q);",
			tblName,
			log->recipient,
			log->startTime,
			log->revision,
			log->lastChange,
			log->fileName);

	// Clean-up:
	g_free(tblName);

	// Execute query:
	if (!PC_LogDB_Query(query)) {
		purple_debug_error("PidginCote", "PC_LogDB_Insert: Unable to insert new entry.\r\n");
		return FALSE;
	}

	// Clean-up:
	sqlite3_free(query);

	// Return:
	return TRUE;
}



/**
 * Deletes the given log from the Database.
 * 	The log is identified by it's primary key:
 * 	Protocol, Account, Recipient, StartDate.
 *
 * @param	log	The log to be deleted from the database.
 * @returns	True on success, false otherwise.
 */
static gboolean	PC_DBTable_Logs_Delete(const PC_Log* log) {
	gchar*			tblName;	// Clean-up: Yes
	gchar*			query;		// Clean-up: Yes
	gchar*			sqlID;		// Clean-up: Yes

	// Check input:
	if (!log) {
		purple_debug_warning("PidginCote", "PC_LogDB_Delete: Missing 'log' parameter.\r\n");
		return FALSE;
	} else if (!log->protocol) {
		purple_debug_warning("PidginCote", "PC_LogDB_Delete: Missing 'log->protocol' parameter.\r\n");
		return FALSE;
	} else if (!log->account) {
		purple_debug_warning("PidginCote", "PC_LogDB_Delete: Missing 'log->account' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_LogDB_Delete: Unable to find an active DB connection.\r\n");
		return FALSE;
	}

	// Fetch table name:
	tblName = PC_LogDB_GetTableName(log->protocol, log->account);
	if (!tblName) {
		purple_debug_error("PidginCote", "PC_LogDB_Delete: Unable to get TableName.\r\n");
		return FALSE;
	}

	// Fetch sqlID:
	sqlID = PC_Log_GetSQLID(log);
	if (!sqlID) {
		purple_debug_error("PidginCote", "PC_LogDB_Delete: Unable to fetch sqlID.\r\n");
		return FALSE;
	}

	// Prepare query:
	query = g_strdup_printf("DELETE FROM %s WHERE %s;", tblName, sqlID);

	// Clean-up:
	g_free(tblName);
	g_free(sqlID);

	// Execute query:
	if (!PC_LogDB_Query(query)) {
		purple_debug_error("PidginCote", "PC_LogDB_Insert: Unable to delete entry.\r\n");
		return FALSE;
	}

	// Clean-up:
	g_free(query);

	// Return:
	return TRUE;
}



/**
 * Updates a log in the database.
 *
 * @param	originalLog	The original log in the database.
 * @param	newLog		The new log to replace the original one.
 * @returns	True on success, False otherwise.
 */
static gboolean	PC_DBTable_Logs_Update(const PC_Log* originalLog, const PC_Log* newLog) {
	gchar*	sqlID;		// Clean-up: Yes
	gchar*	query;		// Clean-up: Yes
	gchar*	tblName;	// Clean-up: Yes
	gchar*	tmp;		// Clean-up: Yes
	char*	newPart;	// Clean-up: Yes

	// Check input:
	if (!originalLog) {
		purple_debug_warning("PidginCote", "PC_LogDB_Update: Missing 'originalLog' parameter.\r\n");
		return FALSE;
	} else if (!newLog) {
		purple_debug_warning("PidginCote", "PC_LogDB_Update: Missing 'newLog' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_LogDB_Update: Unable to find an active DB connection.\r\n");
		return FALSE;
	}

	// Build SQL ID:
	sqlID = PC_Log_GetSQLID(originalLog);
	if (!sqlID) {
		purple_debug_warning("PidginCote", "PC_LogDB_Update: Unable to find unique identifier for original log.\r\n");
		return FALSE;
	}

	// Fetch table name:
	tblName = PC_LogDB_GetTableName(originalLog->protocol, originalLog->account);
	if (!tblName) {
		purple_debug_warning("PidginCote", "PC_LogDB_Update: Unable to fetch table name.\r\n");
		return FALSE;
	}

	// Build parts:
	query = NULL;
	if (newLog->recipient) {
		// New part:
		newPart = sqlite3_mprintf("recipient = %Q", newLog->recipient);
		tmp = query;
		query = g_strjoin(", ", newPart, query, NULL);

		// Clean-up:
		sqlite3_free(newPart);
		g_free(tmp);
	}
	if (newLog->startTime) {
		// New part:
		newPart = sqlite3_mprintf("startDate = %i", newLog->startTime);
		tmp = query;
		query = g_strjoin(", ", newPart, query, NULL);

		// Clean-up:
		sqlite3_free(newPart);
		g_free(tmp);
	}
	if (newLog->revision >= 0) {
		// New part:
		newPart = sqlite3_mprintf("revision = %i", newLog->revision);
		tmp = query;
		query = g_strjoin(", ", newPart, query, NULL);

		// Clean-up:
		sqlite3_free(newPart);
		g_free(tmp);
	}
	if (newLog->lastChange) {
		// New part:
		newPart = sqlite3_mprintf("lastChange = %i", newLog->lastChange);
		tmp = query;
		query = g_strjoin(", ", newPart, query, NULL);

		// Clean-up:
		sqlite3_free(newPart);
		g_free(tmp);
	}
	if (newLog->fileName) {
		// New part:
		newPart = sqlite3_mprintf("fileName = %Q", newLog->fileName);
		tmp = query;
		query = g_strjoin(", ", newPart, query, NULL);

		// Clean-up:
		sqlite3_free(newPart);
		g_free(tmp);
	}

	// Detect empty query:
	if (!query) {
		purple_debug_info("PidginCote", "PC_LogDB_Update: Given log contains no information.\r\n");
		return TRUE;
	}

	// Build query:
	newPart = sqlite3_mprintf("UPDATE %s SET %s WHERE %s;",
			tblName,
			query,
			sqlID);

	// Clean-up:
	g_free(query);
	g_free(tblName);
	g_free(sqlID);


	// Execute query:
	if (!PC_LogDB_Query(newPart)) {
		purple_debug_error("PidginCote", "PC_LogDB_Update: Unable to update log.\r\n");
		return FALSE;
	}

	// Clean-up:
	sqlite3_free(newPart);

	// Return:
	return TRUE;
}


/**
 * Checks if the given log exists in the database.
 *
 * @param 	log	The log to check for existence.
 * @returns True if the given log exists, false otherwise.
 */
static gboolean PC_DBTable_Logs_Exists(const PC_Log* log) {
	gchar*			tableName;	// Clean-up: Yes
	gchar*			sqlID;		// Clean-up: Yes
	gchar*			query;		// Clean-up: Yes
	sqlite3_stmt*	stmt;		// Clean-up: Yes
	PC_Log*			dbLog;		// Clean-up: Yes
	gboolean		result;		// Clean-up: No

	// Check input:
	if (!log) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_Exists: Missing 'log' parameter.\r\n");
		return FALSE;
	} else if (!log->protocol) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_Exists: Missing 'log->protocol' parameter.\r\n");
		return FALSE;
	} else if (!log->account) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_Exists: Missing 'log->account' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_Exists: Unable to find an active DB connection.\r\n");
		return FALSE;
	}

	// Fetch tableName:
	tableName = PC_LogDB_GetTableName(log->protocol, log->account);
	if (!tableName) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_Exists: Unable to fetch tableName.\r\n");
		return FALSE;
	}

	// Fetch sqlID:
	sqlID = PC_Log_GetSQLID(log);
	if (!sqlID) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_Exists: Unable to fetch sqlID.\r\n");
		return FALSE;
	}

	// Prepare query:
	query = g_strdup_printf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, sqlID);

	// Clean-up:
	g_free(tableName);
	g_free(sqlID);

	// Make statement:
	stmt = NULL;
	if (sqlite3_prepare_v2(pc_logDB, query, -1, &stmt, NULL) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_Exists: Unable to prepare statement due to SQLite error.\r\n");
		return FALSE;
	} else if (!stmt) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_Exists: Unable to prepare statement due to unknown error.\r\n");
		return FALSE;
	}

	// Fetch one PC_Log:
	dbLog = PC_DBTable_Logs_FetchOne(stmt);

	// Determine result:
	if (dbLog) {
		result = TRUE;

		// Clean-up:
		PC_Log_Free(dbLog);
		log = NULL;
	} else {
		result = FALSE;
	}

	// Clean-up:
	g_free(query);
	sqlite3_finalize(stmt);

	// Return result:
	return result;
}


/**
 * Fetches all logs from the given users database with revision 0.
 *
 * @param 	account	The account to fetch the logs from.
 * @returns A GList containing the PC_Log objects with revision 0.
 */
static GList* PC_DBTable_Logs_GetRev0(const PurpleAccount* account) {
	gchar*			tableName;	// Clean-up: Yes
	gchar*			query;		// Clean-up: Yes
	sqlite3_stmt*	stmt;		// Clean-up: Yes
	GList*			retList;	// Clean-up: No
	PC_Log*			curLog;		// Clean-up: No

	// Check input:
	if (!account) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_GetRev0: Missing 'account' parameter.\r\n");
		return NULL;
	} else if (!account->protocol_id) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_GetRev0: Missing 'account->protocol_id' parameter.\r\n");
		return NULL;
	} else if (!account->username) {
		purple_debug_warning("PidginCote", "PC_DBTable_Logs_GetRev0: Missing 'account->username' parameter.\r\n");
		return NULL;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_GetRev0: Unable to find an active DB connection.\r\n");
		return FALSE;
	}

	// Fetch tableName:
	tableName = PC_LogDB_GetTableName(account->protocol_id, PC_Util_ParseUsername(account->username));
	if (!tableName) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_GetRev0: Unable to fetch tableName.\r\n");
		return FALSE;
	}

	// Prepare query:
	query = g_strdup_printf("SELECT * FROM %s WHERE revision <= 0", tableName);

	// Clean-up:
	g_free(tableName);

	// Make statement:
	stmt = NULL;
	if (sqlite3_prepare_v2(pc_logDB, query, -1, &stmt, NULL) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_GetRev0: Unable to prepare statement due to SQLite error.\r\n");
		return FALSE;
	} else if (!stmt) {
		purple_debug_error("PidginCote", "PC_DBTable_Logs_GetRev0: Unable to prepare statement due to unknown error.\r\n");
		return FALSE;
	}

	// Fetch all PC_Log:
	retList = NULL;
	curLog = PC_DBTable_Logs_FetchOne(stmt);
	while (curLog) {
		// Fill protocol and account:
		curLog->protocol = g_strdup(account->protocol_id);
		curLog->account = PC_Util_ParseUsername(account->username);

		// Add to list:
		retList = g_list_prepend(retList, curLog);

		// Next:
		curLog = PC_DBTable_Logs_FetchOne(stmt);
	}

	// Clean-up:
	g_free(query);
	sqlite3_finalize(stmt);

	// Return result:
	return retList;
}
